﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ColourCreator.Properties;

namespace ColourCreator.Classes
{
    static class Generator
    {
        private const string CsPattern =
           @"public \s+ override \s+ Colour \s+ (?<Property>\w+) \s* \{ \s*
            get \s* \{ \s* return \s+ Colour\.From
            (( Name \( \s* ""(?<Name>\w+)"" \s* \) ) |
            ( Argb \( (\s*(?<A>\d+)\s*,)? \s* (?<R>\d+) \s*,\s* (?<G>\d+) \s*,\s* (?<B>\d+) \s* \) ))
            ; \s* \} \s* \}";
        private const string VbPattern =
           @"Public \s+ Overrides \s+ ReadOnly \s+ Property \s+ (?<Property>\w+)\(\) \s+ As \s+ Colour \s*
            Get \s* Return \s+ Colour\.From
            (( Name \( \s* ""(?<Name>\w+)"" \s* \) ) |
            ( Argb \( (\s*(?<A>\d+)\s*,)? \s* (?<R>\d+) \s*,\s* (?<G>\d+) \s*,\s* (?<B>\d+) \s* \) ))
            \s+ End \s+ Get";

        private static readonly string CsTemplate = Settings.Default.Template;
        private static readonly string VbTemplate = Settings.Default.TemplateVB;
        private static readonly string Header = Settings.Default.AutoGeneratedHeader;
        private static readonly string CsComment = Settings.Default.CommentCS;
        private static readonly string VbComment = Settings.Default.CommentVB;
        private static readonly string CsPropertyNameTemplate = Settings.Default.PropertyTemplateName;
        private static readonly string VbPropertyNameTemplate = Settings.Default.PropertyTemplateNameVB;
        private static readonly string CsPropertyArgbTemplate = Settings.Default.PropertyTemplateArgb;
        private static readonly string VbPropertyArgbTemplate = Settings.Default.PropertyTemplateArgbVB;

        public static void SaveAs(CustomisableColourTable table, string filePath)
        {
            if (table == null) throw new ArgumentNullException("table");
            if (filePath == null) throw new ArgumentNullException("filePath");

            // VB or C#?
            bool vb = IsVbFile(filePath);

            // Get user-defined namespace and class name.
            string nameSpace = Settings.Default.DefaultNamespace;
            string className = GetClassName(filePath);
            StringBuilder properties = new StringBuilder();

            // For each color in color table.
            //IEnumerable<ColourTableGroup> values = Enum.GetValues(
            //    typeof(ColourTableGroup)).Cast<ColourTableGroup>();

            //foreach (ColourTableGroup colourGroup in values)
            //{
            //    // Color and name of the property.
            //    Color colour = table[colourGroup];
            //    string propertyName = Enum.GetName(typeof(ColourTableGroup), colourGroup);

            //    // Templates for Color.FromArgb and Color.FromName.
            //    string propertyTemplateArgb = vb ? VbPropertyArgbTemplate
            //                                     : CsPropertyArgbTemplate;
            //    string propertyTemplateName = vb ? VbPropertyNameTemplate
            //                                     : CsPropertyNameTemplate;

            //    // Compose property.
            //    string property;
            //    if (colour.IsNamedColor)
            //    {
            //        property = string.Format(CultureInfo.InvariantCulture,
            //                                 propertyTemplateName, propertyName,
            //                                 colour.Name);
            //    }
            //    else
            //    {
            //        property = string.Format(CultureInfo.InvariantCulture,
            //                                 propertyTemplateArgb, propertyName,
            //                                 colour.A, colour.R, colour.G, colour.B);
            //    }

            //    // Append to list.
            //    properties.AppendLine(property);
            //}

            string header = Settings.Default.IncludeHeader
                                ? string.Format(
                                    CultureInfo.InvariantCulture,
                                    Header, vb ? VbComment : CsComment)
                                : string.Empty;

            // Generate output.
            string output = string.Format(
                CultureInfo.InvariantCulture,
                vb ? VbTemplate : CsTemplate,
                header, nameSpace, className, properties);

            File.WriteAllText(filePath, output);
        }

        public static void LoadFrom(CustomisableColourTable table, string filePath)
        {
            if (table == null) throw new ArgumentNullException("table");
            if (filePath == null) throw new ArgumentNullException("filePath");

            // VB or C#?
            bool vb = IsVbFile(filePath);

            Regex regex = new Regex(
                vb ? VbPattern : CsPattern,
                RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace |
                RegexOptions.Multiline | RegexOptions.IgnoreCase);

            // Try to open and read file.
            string text = File.ReadAllText(filePath);

            Match match = regex.Match(text);
            if (!match.Success) throw new InvalidOperationException();

            // Reset all colors to their default values.
            table.InitFromBase(true);

            bool modified = false;
            while (match.Success)
            {
                string property = match.Groups["Property"].Value;
                string name = match.Groups["Name"].Value;

                Color colour;
                if (!string.IsNullOrEmpty(name))
                {
                    colour = Color.FromName(name);
                }
                else
                {
                    int r = int.Parse(match.Groups["R"].Value);
                    int g = int.Parse(match.Groups["G"].Value);
                    int b = int.Parse(match.Groups["B"].Value);

                    // Alpha chanel is optional.
                    int a;
                    if (!int.TryParse(match.Groups["A"].Value, out a)) a = 255;

                    colour = Color.FromArgb(a, r, g, b);
                }

                try
                {
                    ColourTableGroup colourGroup = (ColourTableGroup)Enum.Parse(
                        typeof(ColourTableGroup), property);
                    table[colourGroup] = colour;
                    modified = true;
                }
                catch (ArgumentException)
                {
                }

                match = match.NextMatch();
            }

            if (modified)
            {
                table.MakeColorsDefault();
            }
        }

        private static string GetClassName(string fileName)
        {
            var name = new StringBuilder(Path.GetFileNameWithoutExtension(fileName));
            for (int i = name.Length - 1; i >= 0; i--)
            {
                if (!Char.IsLetterOrDigit(name[i]) && name[i] != '_')
                {
                    name.Remove(i, 1);
                }
            }

            if (name.Length == 0)
            {
                return "MyColorTable";
            }
            else if (Char.IsDigit(name[0]))
            {
                name.Insert(0, '_');
            }

            return name.ToString();
        }

        private static bool IsVbFile(string filePath)
        {
            if (filePath == null) throw new ArgumentNullException("filePath");

            bool vb = false;
            string ext = Path.GetExtension(filePath);
            if (!string.IsNullOrEmpty(ext))
            {
                vb = ext.Equals(".vb", StringComparison.OrdinalIgnoreCase);
            }

            return vb;
        }
    }
}